package com.sigmatrix.h5.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.sigmatrix.h5.components.RedisClient;
import com.sigmatrix.h5.dao.AdminAreaDao;
import com.sigmatrix.h5.entity.AdminArea;
import com.sigmatrix.h5.enums.BaiduMapStatus;
import com.sigmatrix.h5.enums.CoordType;
import com.sigmatrix.h5.exception.MessageException;
import com.sigmatrix.h5.service.AdminAreaService;
import com.sigmatrix.h5.utils.Assert;
import com.sigmatrix.h5.utils.CommonUtils;
import com.sigmatrix.h5.utils.baidu.BaiduMapUtils;
import com.sigmatrix.h5.utils.baidu.po.AddressComponent;
import com.sigmatrix.h5.utils.baidu.po.LatLngLocation;
import com.sigmatrix.h5.web.mode.SigmatrixLocationWrapper;
import com.sigmatrix.sc.jdbc.common.service.ServiceImpl;
/**
 * 
 *@ClassName: AdminAreaServiceImpl
 *@Description: 
 *@author MH
 *@date 2017年9月25日 下午1:41:54
 */
@Service
public class AdminAreaServiceImpl extends ServiceImpl<AdminArea,Integer> implements AdminAreaService{
	private static final String UNDER_LINE = "_";
	private static final short PROVINCE_TYPE = 1;
	private static final short CITY_TYPE = 2;
	private static final short DISTRICT_TYPE = 3;

	/**
	 * key：省,value:省市区信息。
	 * 忽略初始化并发场景
	 */
	private ConcurrentHashMap<String, Map<String,AdminArea>> cachAdminArea = new ConcurrentHashMap<>(35);
	
	private ConcurrentHashMap<Integer, AdminArea> idToEntityMap = new ConcurrentHashMap<>(350);
	
	@Autowired
	AdminAreaDao adminAreaDao;
	
	@Autowired
	RedisClient redisClient;
	
	private final String REDIS_AREA_KEY = "areaList";
	
	@Override
	public List<AdminArea> findByParentId(Integer parentId){
		if(CommonUtils.isEmpty(parentId)){
			parentId = 0;
		}
		AdminArea area = new AdminArea();
		area.setParent(parentId);
		Map<String,String> order = new HashMap<String,String>(20);
		order.put("id", "");
		return select(area,order);
	}

	@Override
	public List<AdminArea> findByIds(Object... ids) {
	
		return adminAreaDao.findByIds(ids);
	}

	@Override
	public List<AdminArea> findByAllByCache() {
		String areaStr = redisClient.get(REDIS_AREA_KEY);
		if(StringUtils.isBlank(areaStr)){
			List<AdminArea> list = select(null);
			redisClient.set(REDIS_AREA_KEY, JSONObject.toJSONString(list),-1);
			return list;
		}else{
			return JSONObject.parseArray(areaStr, AdminArea.class);
		}
	}
	@Override
	public List<AdminArea> findProvinceAndCity() {
		return findByAllByCache().stream().filter(x -> x.getType() < 3).collect(Collectors.toList());
	}

	@Override
	public void reload() {
		load();
	}

	private synchronized void load() {
		List<AdminArea> list = select(null);
		// 以AdminArea.id为key
		Map<Integer, AdminArea> all = idToEntityMap;
		for (AdminArea adminArea : list) {
			if (PROVINCE_TYPE == adminArea.getType().shortValue()) {
				cachAdminArea.put(adminArea.getName() + UNDER_LINE + PROVINCE_TYPE, new HashMap<>(35));
			}
			idToEntityMap.put(adminArea.getId(), adminArea);
		}
		for (AdminArea adminArea : list) {
			if (PROVINCE_TYPE == adminArea.getType().shortValue()) {
				Map<String, AdminArea> map = cachAdminArea.get(adminArea.getName() + UNDER_LINE + PROVINCE_TYPE);
				map.put(adminArea.getName() + UNDER_LINE + adminArea.getType(), adminArea);
			} else if (CITY_TYPE == adminArea.getType().shortValue()) {
				AdminArea province = all.get(adminArea.getParent());
				Map<String, AdminArea> map = cachAdminArea.get(province.getName() + UNDER_LINE + province.getType());
				map.put(adminArea.getName() + UNDER_LINE + adminArea.getType(), adminArea);
			} else if (DISTRICT_TYPE == adminArea.getType().shortValue()) {
				AdminArea city = all.get(adminArea.getParent());
				AdminArea province = all.get(city.getParent());
				Map<String, AdminArea> map = cachAdminArea.get(province.getName() + UNDER_LINE + province.getType());
				map.put(adminArea.getName() + UNDER_LINE + adminArea.getType(), adminArea);
			}
		}
	}

	/**
	 * 获取城市
	 * @param cityName e.g. 苏州市
	 * @param provinceName e.g. 江苏省
	 * @return AdminArea
	 */
	private AdminArea getCity(String cityName, String provinceName) {
		if (cachAdminArea.isEmpty()) {
			load();
		}
		Map<String, AdminArea> map = cachAdminArea.get(provinceName + UNDER_LINE + PROVINCE_TYPE);
		return map.get(cityName + UNDER_LINE + CITY_TYPE);
	}


	
	/**
	 * 获取省
	 * @param provinceName e.g. 江苏省
	 * @return AdminArea
	 */
	private AdminArea getProvince(String provinceName) {
		if (cachAdminArea.isEmpty()) {
			load();
		}
		Map<String, AdminArea> map = cachAdminArea.get(provinceName + UNDER_LINE + PROVINCE_TYPE);
		return map.get(provinceName + UNDER_LINE + PROVINCE_TYPE);
	}

	
	/**
	 * 获取区
	 * @param districtName e.g. 安平县
	 * @param provinceName e.g. 江苏省
	 * @return
	 */
	private AdminArea getDistrict(String districtName, String provinceName) {
		if (cachAdminArea.isEmpty()) {
			load();
		}
		Map<String, AdminArea> map = cachAdminArea.get(provinceName + UNDER_LINE + PROVINCE_TYPE);
		return map.get(districtName + UNDER_LINE + DISTRICT_TYPE);
	}

	@Override
	public SigmatrixLocationWrapper getLocation(String latitude, String longitude, CoordType coordType) {
		Assert.notNull(latitude, "入参不合法：经纬度");
		Assert.notNull(longitude, "入参不合法：经纬度");
		Assert.notNull(coordType, "入参不合法:地图坐标类型");
		LatLngLocation location = BaiduMapUtils.parseLatAndLng(latitude, longitude, coordType);
		if (!BaiduMapStatus.OK.checkValue(location.getStatus())) {
			throw new MessageException("定位失败");
		}

		AddressComponent addr = location.getResult().getAddressComponent();
		if (CommonUtils.isEmpty(addr)) {
			throw new MessageException("定位失败");
		}
		
		if(CommonUtils.isEmpty(addr.getProvince())||CommonUtils.isEmpty(addr.getCity())) {
			throw new MessageException("定位失败");
		}
		
		
		
		AdminArea province = getProvince(addr.getProvince());
		if (province == null) {
			throw new MessageException("定位失败");
		}
		AdminArea city = getCity(addr.getCity(), addr.getProvince());
		AdminArea district = getDistrict(addr.getDistrict(), addr.getProvince());
		if (city == null && district == null) {
			throw new MessageException("定位失败");
		}
		SigmatrixLocationWrapper wrapper = new SigmatrixLocationWrapper();
		wrapper.setAddress(location.getResult().getFormattedAddress());
		wrapper.setProvince(province.getId());
		wrapper.setLatitude(latitude);
		wrapper.setLongitude(longitude);
		if (city != null && district != null && !district.getParent().equals(city.getId())) {
			wrapper.setCity(district.getParent());
			wrapper.setCitySubOrdinate(district.getId());
		}
		if (city != null && district != null) {
			wrapper.setCity(city.getId());
			wrapper.setCitySubOrdinate(district.getId());
		}
		if (city == null && district != null) {
			wrapper.setCity(district.getParent());
			wrapper.setCitySubOrdinate(district.getId());
		}
		if (city != null && district == null) {
			wrapper.setCity(city.getId());
		}
		//add 名称
		AdminArea pro = findByIdFromCache(wrapper.getProvince());
		if(pro!=null){			
			wrapper.setProvinceName(pro.getName());
		}
		AdminArea ci = findByIdFromCache(wrapper.getCity());
		if(ci!=null){			
			wrapper.setCityName(ci.getName());
		}
		AdminArea co = findByIdFromCache(wrapper.getCitySubOrdinate());
		if(co!=null){			
			wrapper.setCountyName(co.getName());
		}
		return wrapper;
	}

	@Override
	public SigmatrixLocationWrapper getLocation(String latitude, String longitude) {
		return getLocation(latitude, longitude, CoordType.GCJ02LL);
	}

	@Override
	public AdminArea findByIdFromCache(Integer id) {
		if(idToEntityMap.isEmpty()){
			load();
		}
		return idToEntityMap.get(id);
	}
	
}
